#pragma once

#include <poll.h>
#include <iostream>
#include <string>
#include <algorithm>
#include "Socket.hpp"

static const int max_pollfd_cnt = 64;
static const int timeout = 2000;
/*
int poll(struct pollfd *fds, nfds_t nfds, int timeout);
    The  field  fd  contains a file descriptor for an open file.
    If this field is negative,  then  the  corresponding  events
    field  is ignored and the revents field returns zero.  (This
    provides an easy way of ignoring a  file  descriptor  for  a
    single  poll() call: simply negate the fd field.  Note, how‐
    ever, that this technique can't be used to ignore  file  de‐
    scriptor 0.)
*/
static const int defaultfd = -1;

class PollServer
{
public:
    PollServer(int port)
        :_port(port)
    {}

    void Init()
    {
        _listenSock.Sock();
        _listenSock.Bind(_port);
        _listenSock.Listen();
        for(int i = 0; i < max_pollfd_cnt; ++i) {
            pollfds[i].fd = defaultfd;
            pollfds[i].events = 0;
        }
        int listenfd = _listenSock.Fd();
        struct pollfd listen; bzero(&listen, sizeof(listen));
        listen.fd = listenfd;
        listen.events = POLLIN;
        pollfds[0] = listen;
    }

    void Accepter()
    {
        std::string clinetip; uint16_t clinetport = 0;
        int newfd = _listenSock.Accept(&clinetip, &clinetport);
        std::cerr << "get a new link, ip: " << clinetip << \
            " , port: " << clinetport  << \
            " , fd: " << newfd << std::endl;
        struct pollfd newPollFd; bzero(&newPollFd, sizeof(newPollFd));
        newPollFd.fd = newfd;
        newPollFd.events = POLLIN;
        for(int i = 0; i < max_pollfd_cnt; ++i) {
            if(pollfds[i].fd != defaultfd) {
                pollfds[i] = newPollFd; break;
            }
        }
    }

    void Recver(int pos)
    {
        char buff[1024] = { 0 };
        ssize_t n = read(pollfds[pos].fd, buff, sizeof(buff) - 1);
        if(n < 0) { std::cerr << "read err" << std::endl; }
        else if(n > 0) {
            buff[n] = 0;
            std::cout << "echo# " << buff << std::endl;
        }
        else {
            int oldfd = pollfds[pos].fd;
            close(pollfds[pos].fd);
            pollfds[pos].fd = defaultfd;
            pollfds[pos].events = 0;
            std::cerr << "close fd, fd: " << oldfd << std::endl;
        }
    }

    void Dispatcher()
    {
        int listenfd = _listenSock.Fd();
        for(int i = 0; i < max_pollfd_cnt; ++i) {
            if(pollfds[i].fd == defaultfd) { continue; }
            //读事件就绪
            if(pollfds[i].revents & POLLIN)
            {
                if(pollfds[i].fd == listenfd) {
                    Accepter();
                }
                else {
                    Recver(i);
                }
            }
        }
    }

    void Run()
    {
        int listenfd = _listenSock.Fd();
        while(true)
        {
            int ret  = poll(pollfds, max_pollfd_cnt, timeout);
            if(ret == 0) {
                std::cerr << "time out" << std::endl;
            }
            else if(ret < 0) {
                std::cerr << "poll err" << std::endl;
            }
            else {
                Dispatcher();
            }
        }
    }

private:
    Socket _listenSock;
    int _port;
    struct pollfd pollfds[max_pollfd_cnt];
};
